home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
pattern.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
19KB
|
856 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include "mutt_regex.h"
#include "mapping.h"
#include "keymap.h"
#include "mailbox.h"
#include "state.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef _PGPPATH
#include "pgp.h"
#endif
#define new_pattern() calloc(1, sizeof (pattern_t))
typedef struct pattern_t
{
short op;
short not;
time_t notbefore;
time_t notafter;
int minmsg;
int maxmsg;
struct pattern_t *next;
struct pattern_t *child; /* arguments to logical op */
regex_t rx;
} pattern_t;
static const char *eat_regexp (pattern_t *pat, const char *s, char *, size_t);
static const char *eat_date (pattern_t *pat, const char *s, char *, size_t);
static const char *eat_range (pattern_t *pat, const char *s, char *, size_t);
static int mutt_pattern_exec (struct pattern_t *pat, CONTEXT *ctx, HEADER *h);
struct pattern_flags
{
int tag; /* character used to represent this op */
int op; /* operation to perform */
const char *(*eat_arg) (pattern_t *, const char *, char *, size_t);
}
Flags[] =
{
{ 'A', M_ALL, NULL },
{ 'D', M_DELETED, NULL },
{ 'F', M_FLAG, NULL },
{ 'N', M_NEW, NULL },
{ 'O', M_OLD, NULL },
{ 'R', M_READ, NULL },
{ 'Q', M_REPLIED, NULL },
{ 'T', M_TAG, NULL },
{ 'U', M_UNREAD, NULL },
{ 'b', M_BODY, eat_regexp },
{ 'c', M_CC, eat_regexp },
{ 'd', M_DATE, eat_date },
{ 'e', M_SENDER, eat_regexp },
{ 'f', M_FROM, eat_regexp },
{ 'h', M_HEADER, eat_regexp },
{ 'i', M_ID, eat_regexp },
{ 'm', M_MESSAGE, eat_range },
{ 'r', M_DATE_RECEIVED, eat_regexp },
{ 's', M_SUBJECT, eat_regexp },
{ 't', M_TO, eat_regexp },
{ 0 }
};
static pattern_t *SearchPattern = NULL; /* current search pattern */
static char LastSearch[STRING] = { 0 }; /* last pattern searched for */
int mutt_getvaluebychar (char ch, struct mapping_t *table)
{
int i;
for (i = 0; table[i].name; i++)
{
if (ch == table[i].name[0])
return table[i].value;
}
return (-1);
}
/* if no uppercase letters are given, do a case-insensitive search */
int mutt_which_case (const char *s)
{
while (*s)
{
if (isalpha (*s) && isupper (*s))
return 0; /* case-sensitive */
s++;
}
return REG_ICASE; /* case-insensitive */
}
static int
msg_search (regex_t *rx, char *buf, size_t blen, int is_hdr, int msgno)
{
char tempfile[_POSIX_PATH_MAX];
MESSAGE *msg = NULL;
STATE s;
struct stat st;
FILE *fp = NULL;
long lng;
int match = 0;
if ((msg = mx_open_message (Context, msgno)) != NULL)
{
if (option (OPTTHOROUGHSRC))
{
/* decode the header / body */
memset (&s, 0, sizeof (s));
s.fpin = msg->fp;
mutt_mktemp (tempfile);
if ((s.fpout = safe_fopen (tempfile, "w+")) == NULL)
{
mutt_perror (tempfile);
return (0);
}
if (is_hdr)
mutt_copy_header (msg->fp, Context->hdrs[msgno], s.fpout, CH_FROM | CH_DECODE);
else
{
mutt_parse_mime_message (Context->hdrs[msgno]);
#ifdef _PGPPATH
if (Context->hdrs[msgno]->pgp & PGPENCRYPT && !pgp_valid_passphrase())
{
mx_close_message (&msg);
fclose (fp);
unlink (tempfile);
return (0);
}
#endif
fseek (msg->fp, Context->hdrs[msgno]->offset, 0);
mutt_body_handler (Context->hdrs[msgno]->content, &s);
}
fp = s.fpout;
fflush (fp);
fseek (fp, 0, 0);
fstat (fileno (fp), &st);
lng = (long) st.st_size;
}
else
{
/* raw header / body */
fp = msg->fp;
if (is_hdr)
{
fseek (fp, Context->hdrs[msgno]->offset, 0);
lng = Context->hdrs[msgno]->content->offset - Context->hdrs[msgno]->offset;
}
else
{
fseek (msg->fp, Context->hdrs[msgno]->content->offset, 0);
lng = Context->hdrs[msgno]->content->length;
}
}
/* search the file "fp" */
while (lng > 0)
{
if (fgets (buf, blen - 1, fp) == NULL)
break; /* don't loop forever */
if (regexec (rx, buf, 0, NULL, 0) == 0)
{
match = 1;
break;
}
lng -= strlen (buf);
}
mx_close_message (&msg);
if (option (OPTTHOROUGHSRC))
{
fclose (fp);
unlink (tempfile);
}
}
return match;
}
static const char *
eat_regexp (pattern_t *pat, const char *s, char *err, size_t errlen)
{
char buf[SHORT_STRING];
char expn[SHORT_STRING];
const char *ps;
int r;
ps = mutt_extract_token (buf, sizeof (buf), s, expn, sizeof (expn),
M_PATTERN | M_COMMENT | M_NULL);
if ((r = REGCOMP (&pat->rx, buf, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf))) != 0)
{
regerror (r, &pat->rx, err, errlen);
regfree (&pat->rx);
return NULL;
}
return ps;
}
static const char *
eat_range (pattern_t *pat, const char *s, char *err, size_t errlen)
{
const char *p;
char *tmp;
if (*s != '-')
{
/* range minimum */
pat->minmsg = strtol (s, &tmp, 0) - 1;
p = tmp;
}
else
{
s++;
p = s;
}
if (*p != '-')
{
pat->maxmsg = pat->minmsg;
return p;
}
p++;
if (isdigit (*p))
{
/* range max */
pat->maxmsg = strtol (p, &tmp, 0) - 1;
p = tmp;
}
else
pat->maxmsg = Context->msgcount - 1;
return p;
}
static const char *
getDate (const char *s, struct tm *t, char *err, size_t errlen)
{
char *p;
time_t now = time (NULL);
struct tm *tm = localtime (&now);
t->tm_mday = strtol (s, &p, 0);
if (t->tm_mday < 1 || t->tm_mday > 31)
{
snprintf (err, errlen, "Invalid day of month: %s", s);
return NULL;
}
if (*p != '/')
{
/* fill in today's month and year */
t->tm_mon = tm->tm_mon;
t->tm_year = tm->tm_year;
return p;
}
p++;
t->tm_mon = strtol (p, &p, 0) - 1;
if (t->tm_mon < 0 || t->tm_mon > 11)
{
snprintf (err, errlen, "Invalid month: %s", p);
return NULL;
}
if (*p != '/')
{
t->tm_year = tm->tm_year;
return p;
}
p++;
t->tm_year = strtol (p, &p, 0);
if (t->tm_year > 1900)
t->tm_year -= 1900;
return p;
}
/* returns local - UTC in secodnds */
static int mutt_local_tz (void)
{
time_t tz, now = time (NULL);
int yday;
struct tm *tm;
tm = localtime (&now);
tz = tm->tm_hour * 3600 + tm->tm_min * 60;
yday = tm->tm_yday;
tm = gmtime (&now);
tz -= tm->tm_hour * 3600 + tm->tm_min * 60;
yday -= tm->tm_yday;
/* if UTC is on a different day from local, add 24 hours to get the offset */
tz += 86400 * yday;
return (tz);
}
static const char *
eat_date (pattern_t *pat, const char *s, char *err, size_t errlen)
{
struct tm min;
struct tm max;
time_t tz;
memset (&min, 0, sizeof (min));
memset (&max, 0, sizeof (max));
/* Arbitrary year in the future. Don't set this too high
* or mutt_mktime() returns something larger than will
* fit in a time_t on some systems
*/
max.tm_year = 130;
max.tm_mon = 11;
max.tm_mday = 31;
max.tm_hour = 23;
max.tm_min = 59;
max.tm_sec = 59;
if (*s != '-')
{
/* mininum date specified */
if ((s = getDate (s, &min, err, errlen)) == NULL)
return NULL;
}
if (*s && *s == '-')
{
/* max date */
s++; /* skip the `-' */
if (*s)
if ((s = getDate (s, &max, err, errlen)) == NULL)
return NULL;
}
else
{
/* search for messages on a specific day */
max.tm_year = min.tm_year;
max.tm_mon = min.tm_mon;
max.tm_mday = min.tm_mday;
}
tz = mutt_local_tz ();
pat-